#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "DS18B20.h"
#include "Buzzer.h"
#include "Pump.h"
#include "WaterLevel.h"
#include "Powerexamine.h"
#include "LED.h"
#include "EarthWater.h"
#include <math.h>



// 定时器0初始化：定时1ms（晶振11.0592MHz）
void Timer0Init(void) {
    TMOD &= 0xF0;  // 清除定时器0配置
    TMOD |= 0x01;  // 定时器0工作在模式1（16位定时）
    TH0 = 0xFC;    // 初值高8位（计算见注释）
    TL0 = 0x67;    // 初值低8位（1ms定时）
    ET0 = 1;       // 使能定时器0中断
    EA = 1;        // 使能总中断
    TR0 = 1;       // 启动定时器0
}

float temper; //温度
unsigned char recv_dat;  //串口收的数据
uint Earthhumi;    //土壤湿度
int WaterLevel;   //水位
uchar adc0 = 0;
uchar adc1 = 0;
uint voltage1 = 0;
uint voltage0 = 0;
uchar str0[6];   // 存储转换后的字符串（最大5位+结束符）
uchar str1[6]; 
uint Change;   //改变后的湿度
// 定义计数器，用于累计5ms中断次数
unsigned char count = 0;

// 初始化串口：方式1，波特率9600（fosc=11.0592MHz）
void UART_Init() {
    SCON = 0x50;       // 方式1（SM0=0,SM1=1），允许接收（REN=1）
    TMOD = 0x20;       // 定时器1方式2（8位自动重装载）
    TH1 = 0xFD;        // 波特率9600，初值0xFD
    TL1 = 0xFD;        // 自动重装载值
    TR1 = 1;           // 启动定时器1
    // PCON = 0x80;    // 若需波特率加倍，取消注释（SMOD=1）
}

// 发送一个字节
void UART_SendByte(unsigned char dat) {
    SBUF = dat;
    while(TI == 0);
    TI = 0;
}

// 接收一个字节
unsigned char UART_RecvByte() {
    unsigned char dat;
    while(RI == 0);
    dat = SBUF;
    RI = 0;
    return dat;
}

// 发送16位无符号整数（先发送高8位，再发送低8位）
void UART_SendUint(uint ppdata) 
{
    unsigned char high_byte, low_byte;
    
    high_byte = (ppdata >> 8) & 0xFF;  // 提取高8位
    low_byte = ppdata & 0xFF;          // 提取低8位
    
    UART_SendByte(high_byte);        // 发送高8位
    UART_SendByte(low_byte);         // 发送低8位
}

// 发送字符串（以'\0'结尾）
void UART_SendString(uchar *str) {
    while(*str != '\0') {  // 遍历字符串直到结束符
        UART_SendByte(*str);
        str++;
    }
}

// 将uint转换为字符串（返回字符串长度）
uchar UintToString(uint num, uchar *str) {
    uchar temp[5];  // 临时存储倒序数字（最大65535是5位）
    uchar i = 0, j = 0;
    
    // 处理0的特殊情况
    if(num == 0) {
        str[0] = '0';
        str[1] = '\0';
        return 1;
    }
    
    // 提取每一位（倒序存储）
    while(num > 0) {
        temp[i++] = num % 10;  // 取个位
        num /= 10;             // 移除个位
    }
    
    // 反转并转为字符
    while(i > 0) {
        str[j++] = temp[--i] + '0';  // 数字+48='0'~'9'
    }
    str[j] = '\0';  // 字符串结束符
    return j;       // 返回字符串长度
}

void main()
{
	
	Timer0Init();
	
	LED_Init();
	
    DS18B20_ConvertT();
    Delay_ms(1000); // 等待温度转换完成
	
	LED_OFF(); 
	
    LCD_Init();
    LCD_OPENUI();
	
    UART_Init();       // 初始化串口
	
    while(1)
    {
		//读取adc值	
		adc0 = ADC_read_data(0);
		voltage0 = (adc0/255.0f)* 5000.0f;
		adc1 = ADC_read_data(1);
		voltage1 = abs((((adc1/255.0f)* 5000.0f)-5000)/50.0f);
		
		Change = voltage1 * 2;
		if(Change > 100){Change = 100;}
		
		// 转换为字符串
        UintToString(voltage0, str0);  //电压
		UintToString(Change,str1);     //湿度
		

		
		//转换湿度
		Earthhumi = voltage1;
		
		//转换水位
		WaterLevel = Water_SetState();
    

		
		// 发送字符串（可附加提示信息）
        UART_SendString("Voltage0: ");
        UART_SendString(str0);
        UART_SendString("mV\r\n");  // 换行
		
		UART_SendString("Voltage1: ");
        UART_SendString(str1);
        UART_SendString("mV\r\n");  // 换行


		
		//水箱水位不足，蜂鸣器发声，提示须向水箱加水，
		if(WaterLevel ==0)
		{
			Buzzer_SetState(1);
			Pump_SetState(0);
		}
		else if(WaterLevel ==1)
		{
			//实现土壤水分减至25%且温度低于33℃时，自动开启水泵浇水
			//土壤水分达到100%时停止浇水 75%
			if(temper<33 && Change <= 25){Pump_SetState(1);}

			if(Change >= 100){Pump_SetState(0);}
			Buzzer_SetState(0);
		}
		
		//当电源电压正常时，电源指示灯为绿色长亮，
		if(voltage0 <=2500){LED_RED_ON();LED_GREE_off();}
		else {LED_GREE_ON();LED_RED_off();}
		
        
		
    }
}


// 定时器0中断服务函数
void Timer0_ISR(void) interrupt 1
{
    // 重新装载初值，保证每次中断间隔都是5ms
    TH0 = 0xEC;
    TL0 = 0x78;
	count++;
	if(count == 20){
		//转换温度
        DS18B20_ConvertT();
		temper = DS18B20_ReadT();
         /* 温度显示 */
		LCD_OPENUI();
		LCD_ShowNum(1, 6, temper, 2);//刷新温度
		LCD_ShowNum(1, 9, (unsigned long)(temper*10)%10, 1);
		LCD_ShowNum(2, 6, Change,3);//刷新shidu
		count = 0;
	}
    // 在这里添加5ms需要执行的代码
    // 例如：可以设置一个标志位，主函数中检测到标志位后执行相应操作
}




